home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v10n12.arc
/
WINEXT.C
< prev
next >
Wrap
Text File
|
1991-05-30
|
19KB
|
593 lines
// WinExt 1.0 by Fran Finnegan (76244,145)
// Copyright (c) 1991 Finnegan O'Malley & Company Inc. All Rights Reserved.
// First Published in PC Magazine, June 25, 1991
// developed using Microsoft C 5.10 (Medium memory model only)
#include <direct.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NOCOMM // dumb
#include <windows.h>
#include "winext.h"
#include "dlg.h"
//////////////////////////////////////////////////////////////////////
#define WINEXT_OPTIONS 1
#define WINEXT_DIR 1
#define WINEXT_APP 2
#define SHOW_MINIMIZED SW_SHOWMINNOACTIVE
#define SHOW_MAXIMIZED SW_SHOWMAXIMIZED
#define NO 0
#define YES 1
#define argc __argc
#define argv __argv
extern int argc;
extern char **argv;
typedef struct
{
int iCmdShow;
LPSTR lpsCmdLine;
HANDLE hPrevInst;
HANDLE hInst;
// stack frame prior to WinMain
} NEAR *NPWINMAIN;
extern int PASCAL WinMain
(
HANDLE ahInst,
HANDLE ahPrevInst,
LPSTR alpsCmdLine,
int aiCmdShow
);
extern int FAR PASCAL DlgProc
(
HWND ahDlg,
WORD awMsg,
WORD awParam,
DWORD alParam
);
#pragma alloc_text( _TEXT, WinMain )
#pragma alloc_text( DLGPROC_TEXT, DlgProc )
#define Local(w) LocalLock(LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, w))
#define sizeof_mpsBuffer (512 )
#define sizeof_mpsCmdLine (_MAX_PATH * 2 )
#define sizeof_mpsWinIniExt (256 )
#define sizeof_mpsFileName (_MAX_PATH )
#define sizeof_mpOf sizeof(OFSTRUCT)
static NPWINMAIN mnpWinMain;
static HWND mhDlg; // required for Usage recursion
static POFSTRUCT mpOf; // contains the d:\path\FILENAME.EXT
static BOOL sbUsage;
static char *mpsBuffer ,
*mpsCmdLine , // the New Command Line
*mpsWinIniExt , // ext=string
*mpsFileName ; // d:\path\FILENAME
/******************************************************************************
Usage: WIN.INI [Extensions]: ext=winext [?-+] dir app [args] ^.ext [args]
Program Manager item: winext.exe [?-+] dir app [args] file
where: ext Extension of associated data file (EXT part of FILENAME.EXT)
winext WinExt (WINEXT.EXE should be somewhere on the environment PATH)
?-+ Optional WinExt arguments: ?=dialog; -=minimize; +=maximize
dir Current Working Directory: start-up directory (path, . or ..)
app Program to run: .EXE, .COM, .BAT or .PIF file specification
args Optional app arguments (for embedded blanks, use double-quotes)
^.ext File placeholder: may be ^, ^. or * (ignore .ext, ext or file)
args More optional app arguments (WIN.INI [Extensions] entry only)
file Qualified file specification: may be .\file or * (ignore file)
winext, dir, app, ^.ext and file are required; ?-+ and args are optional ([]s).
dir may be subsequently overridden by a Start-up Directory in an app .PIF file.
path\FILENAME substitutions are made for multiple occurrences of the caret (^).
Environment-variable substitutions are made just as in .BAT files: %variable%.
******************************************************************************/
extern int PASCAL WinMain
(
HANDLE ahInst,
HANDLE ahPrevInst,
LPSTR alpsCmdLine,
int aiCmdShow
)
{
auto char *apsFirst,
*apsLast,
*apsEnv;
auto FARPROC aFpDlgProc;
auto WORD awCode;
auto int aiDialogBox = NO,
aiFileAsterisk = NO;
auto MSG aMsg;
static char sszError[] = "Error.",
sszBlank[] = " ",
sszQuote[] = "\"";
if (NULL == mnpWinMain) // ignore recursion from dialog proc
{
// possibly become a "TSR" on a Load with no arguments
if (0 == ahPrevInst // look for a previous "TSR" instance
&& 1 == argc) // only do this on the first instance
switch (aiCmdShow)
{
case SW_HIDE :
case SW_SHOWMINIMIZED :
case SW_MINIMIZE :
case SW_SHOWMINNOACTIVE:
while (YES) // go into an infinite loop
PeekMessage(&aMsg, 0, WM_NULL, WM_NULL, PM_REMOVE);
// nothing below this line will be executed
}
// remember the first set of WinMain arguments for dialog proc
mnpWinMain = (NPWINMAIN)&aiCmdShow;
// allocate all local storage from largest to smallest
mpsBuffer = Local(sizeof_mpsBuffer );
mpsCmdLine = Local(sizeof_mpsCmdLine );
mpsWinIniExt = Local(sizeof_mpsWinIniExt);
mpsFileName = Local(sizeof_mpsFileName );
mpOf = (POFSTRUCT)Local(sizeof_mpOf );
// verify that allocations succeeded
if (mpsBuffer
&& mpsCmdLine
&& mpsWinIniExt
&& mpsFileName
&& mpOf )
lstrcpy(mpsCmdLine, alpsCmdLine); // to check for '^'
else // a LocalAlloc failed
{
MessageBox(0, sszError, "WinExt", MB_ICONSTOP | MB_OK);
return 0;
}
}
// look for the WinExt options: ?=dialog; -=minimize; +=maximize
if (2 <= argc)
switch (*argv[WINEXT_OPTIONS])
{
case '?':
case '-':
case '+':
while (*argv[WINEXT_OPTIONS])
switch (*(argv[WINEXT_OPTIONS]++))
{
default : // bad option, so show dialog box
case '?': aiDialogBox = YES; break;
case '-': aiCmdShow = SHOW_MINIMIZED; break;
case '+': // if minimize, don't maximize
switch (aiCmdShow)
{
default:
aiCmdShow = SHOW_MAXIMIZED; break;
case SW_HIDE :
case SW_SHOWMINIMIZED :
case SW_MINIMIZE :
case SW_SHOWMINNOACTIVE: break;
}
break;
}
argc--; argv++; // hide WinExt options
break;
}
// there must be at least three arguments: winext dir app ^.ext
if (4 <= argc--
&& NULL == strchr(mpsCmdLine, '^')) // '^' not allowed on Command Line
{
// argv[argc] is probably the ^.ext (FILENAME.EXT), because
// everything after the '^' is ignored by most shells
// check for '*', which means no FILENAME.EXT is to be used
if ('*' == argv[argc][0])
aiFileAsterisk = YES; // turn file-asterisk flag on
else
{
// use the partially- or fully-qualified d:\path\FILENAME.EXT
lstrcpy(mpOf->szPathName, argv[argc]);
if (mpOf->szPathName[0] != '\\' // \filespec
&& mpOf->szPathName[0] != '.' // .\filespec or ..\filespec
&& mpOf->szPathName[1] != ':') // d:filespec or d:\filespec
OpenFile(argv[argc], mpOf, OF_PARSE); // fully-qualified
// get the d:\path\FILENAME (no .EXT) for '^' substitution
lstrcpy(mpsFileName, mpOf->szPathName);
if (apsLast = strrchr(mpsFileName, '.')) // if there's a '.'
{
*apsLast = '\0'; // remove the .EXT
lstrcpy(mpsWinIniExt, ++apsLast); // get the EXT
lstrcat(mpsWinIniExt, "="); // add the '='
// use EXT to get the WIN.INI [Extensions] ext= string
GetProfileString("Extensions", apsLast, "",
mpsWinIniExt + lstrlen(mpsWinIniExt),
sizeof_mpsWinIniExt - (3 + 1));
}
}
// change the Current Working Directory to dir
if (('.' == argv[WINEXT_DIR][0] // check for '.' only
&& '\0' == argv[WINEXT_DIR][1])
|| (':' == argv[WINEXT_DIR][1] // check for "d:" only
&& '\0' == argv[WINEXT_DIR][2])
|| 0 == chdir(argv[WINEXT_DIR])) // change directory
{
// if dir is valid, change drive to any d: in dir
if (':' == argv[WINEXT_DIR][1]) // look for "d:"
_dos_setdrive(argv[WINEXT_DIR][0] & 0x1F, &awCode);
// create the New Command Line, beginning with app
lstrcpy(mpsCmdLine, argv[WINEXT_APP]);
// append any/all args on the left of the FILENAME.EXT
for (argc -= 3, argv += 3; argc; argc--, argv++)
{
lstrcat(mpsCmdLine, sszBlank); // append ' '
if (apsFirst = strchr(*argv, ' ')) // embedded ' '?
lstrcat(mpsCmdLine, sszQuote); // prepend '"'
lstrcat(mpsCmdLine, *argv); // then argument
if (apsFirst) // embedded ' '?
lstrcat(mpsCmdLine, sszQuote); // append '"'
}
// add the d:\path\FILENAME.EXT
if (NO == aiFileAsterisk) // if no '*'
{
lstrcat(mpsCmdLine, sszBlank); // append ' ' and
lstrcat(mpsCmdLine, mpOf->szPathName); // the filespec
}
// look in ext= string for '^' and args on right
if (apsFirst = strchr(mpsWinIniExt, '^'))
{
// assuming the first '^' in ext=, remove the old .EXT
*strrchr(mpsCmdLine, '.') = '\0';
// append ext= string .ext and any args on the right
lstrcat(mpsCmdLine, apsFirst + 1);
}
// do any other substitutions for '^' of d:\path\FILENAME
while (apsFirst = strchr(mpsCmdLine, '^')) // if there's '^'
{
lstrcpy(mpsBuffer, mpsFileName); // d:\path\FILENAME
lstrcat(mpsBuffer, apsFirst + 1); // post-'^' stuff
lstrcpy(apsFirst, mpsBuffer); // New Command Line
}
// do any environment %variable% string substitutions
while ((apsFirst = strchr(mpsCmdLine , '%'))
&& (apsLast = strchr(apsFirst + 1, '%')))
{
*apsLast = mpsBuffer[0] = '\0'; // remove last '%'
if ((apsEnv = getenv( apsFirst + 1 )) // UC/lc
|| (apsEnv = getenv(strupr(apsFirst + 1)))) // UC
lstrcpy(mpsBuffer, apsEnv); // env variable
lstrcat(mpsBuffer, apsLast + 1); // post-'%' stuff
lstrcpy(apsFirst, mpsBuffer); // New Command Line
}
// show the dialog box if it was requested or
// if the New Command Line is too long
apsFirst = strchr(mpsCmdLine, ' '); // first blank after app
if (NULL == apsFirst) // no blank after app
apsFirst = mpsCmdLine + lstrlen(mpsCmdLine);
if (aiDialogBox
|| (apsFirst - mpsCmdLine + 128) < lstrlen(mpsCmdLine)) // too long?
{
aiDialogBox = DialogBox(ahInst, MAKEINTRESOURCE(DLG), 0,
aFpDlgProc = MakeProcInstance(DlgProc, ahInst));
FreeProcInstance(aFpDlgProc);
if (ID_PB_CANCEL == aiDialogBox)
return 0; // premature termination on Cancel
}
// execute the New Command Line
if (32 < (awCode = WinExec(mpsCmdLine, aiCmdShow)))
return 0; // normal termination
// if above Exec fails, fall through and report error code
}
else // requested dir is invalid
{
awCode = 3; // error code for "path not valid" string
lstrcpy(mpsCmdLine, argv[WINEXT_DIR]); // caption is dir
}
// load error text from .RC STRINGTABLE and show message box
if (0 == LoadString(ahInst, awCode, mpsBuffer, sizeof_mpsBuffer))
lstrcpy(mpsBuffer, sszError); // unknown-code string
MessageBox(0, mpsBuffer, mpsCmdLine, MB_ICONSTOP | MB_OK);
}
// put up a "usage" dialog box if requested or if something's wrong
sbUsage = YES;
DialogBox(ahInst, MAKEINTRESOURCE(USAGE), mhDlg,
aFpDlgProc = MakeProcInstance(DlgProc, ahInst));
FreeProcInstance(aFpDlgProc);
sbUsage = NO;
return 0; // error termination
}
//////////////////////////////////////////////////////////////////////
extern int FAR PASCAL DlgProc
(
HWND ahDlg,
WORD awMsg,
WORD awParam,
DWORD alParam
)
{
auto WORD awCode,
awCmdLen;
auto RECT aRt;
auto char *apsCmdLine;
static HWND shCtlExecute,
shCtlCancel ,
shCtlReset ,
shCtlUsage ,
shCtlExt ,
shCtlCWD ,
shCtlPIF ,
shCtlCmd ,
shCtlDefID ;
static WORD swCmdLen;
static int siID_RB_SW;
static char sszPIF[] = ".PIF";
switch (awMsg)
{
case WM_INITDIALOG:
// center dialog box
GetWindowRect(ahDlg, &aRt);
OffsetRect(&aRt, -aRt.left , -aRt.top );
MoveWindow(ahDlg, // this is the correct way to center a dialog:
((GetSystemMetrics(SM_CXSCREEN) - aRt.right ) / 2 + 4) & ~7,
(GetSystemMetrics(SM_CYSCREEN) - aRt.bottom) / 2,
aRt.right , aRt.bottom, NO);
// set dialog caption to module name
GetModuleFileName(mnpWinMain->hInst, mpsBuffer, sizeof_mpsBuffer);
SetWindowText(ahDlg, mpsBuffer);
// if "usage" dialog box, done
if (sbUsage)
{
SetDlgItemText(ahDlg, ID_E_CMD, mnpWinMain->lpsCmdLine);
return YES; // did process the message
}
// save all relevant handles
shCtlDefID =
shCtlExecute = GetDlgItem(ahDlg, ID_PB_EXECUTE);
shCtlCancel = GetDlgItem(ahDlg, ID_PB_CANCEL );
shCtlReset = GetDlgItem(ahDlg, ID_PB_RESET );
shCtlUsage = GetDlgItem(ahDlg, ID_PB_USAGE );
shCtlExt = GetDlgItem(ahDlg, ID_T_EXT );
shCtlCWD = GetDlgItem(ahDlg, ID_T_CWD );
shCtlPIF = GetDlgItem(ahDlg, ID_T_PIF );
shCtlCmd = GetDlgItem(ahDlg, ID_E_CMD );
// set ext= text controls
if (mpsWinIniExt[0]) // WIN.INI [Extensions]
SetWindowText(shCtlExt, mpsWinIniExt);
else // WinExt Command Line
{
GetWindowText(shCtlExt, mpsBuffer, sizeof_mpsBuffer);
SetWindowText(GetDlgItem(ahDlg, ID_GB_EXTBOX), mpsBuffer);
SetWindowText(shCtlExt, mnpWinMain->lpsCmdLine);
}
// set New Command Line edit control
apsCmdLine = strchr(mpsCmdLine, ' '); // first blank after app
if (NULL == apsCmdLine) // no blank after app
apsCmdLine = mpsCmdLine + lstrlen(mpsCmdLine);
swCmdLen = apsCmdLine - mpsCmdLine + 128; // maximum command length
if (swCmdLen < lstrlen(mpsCmdLine)) // is New Command Line longer?
{
GetWindowText(shCtlCWD, mpsBuffer, sizeof_mpsBuffer); // caption
MessageBox(0, mpsCmdLine, mpsBuffer, MB_ICONEXCLAMATION | MB_OK);
mpsCmdLine[swCmdLen] = '\0'; // arguments: ' ' + 127 bytes
}
SendMessage(shCtlCmd, EM_LIMITTEXT, swCmdLen, 0L);
SetWindowText(shCtlCmd, mpsCmdLine); // New Command Line
// set cwd text control // caption of above MessageBox
getcwd(mpsBuffer, sizeof_mpsBuffer); // no trailing '\'
SetWindowText(shCtlCWD, mpsBuffer); // Current Working Directory
// search for a .PIF file
lstrcpy(mpsBuffer , mpsCmdLine);
if ( apsCmdLine = strchr(mpsBuffer, ' ')) // use only app
*apsCmdLine = '\0';
if (':' == mpsBuffer[1]) // remove any d:
lstrcpy(mpsBuffer , mpsBuffer + 2);
if ( apsCmdLine = strrchr(mpsBuffer, '\\')) // remove any path
lstrcpy(mpsBuffer , apsCmdLine + 1);
if ( apsCmdLine = strchr(mpsBuffer, '.')) // rename to .PIF
lstrcpy(apsCmdLine, sszPIF);
else
lstrcat(mpsBuffer , sszPIF);
if (-1 < OpenFile(mpsBuffer , mpOf, OF_EXIST)) // see if .PIF exists
SetWindowText(shCtlPIF, mpOf->szPathName);
else // hide .PIF control
MoveWindow(shCtlPIF, 0, 0, 0, 0, NO);
// set the radio button based on iCmdShow
switch (mnpWinMain->iCmdShow)
{
// case SW_SHOWNORMAL :
// case SW_SHOWNOACTIVATE :
// case SW_SHOW :
// case SW_SHOWNA :
// case SW_RESTORE :
default : siID_RB_SW = ID_RB_DEF; break;
case SW_HIDE :
case SW_SHOWMINIMIZED :
case SW_MINIMIZE :
case SW_SHOWMINNOACTIVE: siID_RB_SW = ID_RB_MIN; break;
case SW_SHOWMAXIMIZED : siID_RB_SW = ID_RB_MAX; break;
}
CheckRadioButton(ahDlg, ID_RB_DEF, ID_RB_MAX, siID_RB_SW);
return YES; // did process the message
case WM_COMMAND:
awCode = HIWORD(alParam);
switch (awParam)
{
case ID_E_CMD:
// enable/disable Execute based on the New Command Line
if (GetWindowTextLength(shCtlCmd))
{
shCtlDefID = shCtlExecute;
SendMessage(ahDlg, DM_SETDEFID, ID_PB_EXECUTE, 0L);
EnableWindow(shCtlExecute, YES);
}
else
{
shCtlDefID = shCtlCancel ;
SendMessage(ahDlg, DM_SETDEFID, ID_PB_CANCEL , 0L);
EnableWindow(shCtlExecute, NO );
}
if (awCode == EN_CHANGE)
{
// enable Reset based on the changed New Command Line
EnableWindow(shCtlReset, YES);
// adjust the maximum size of the New Command Line
GetWindowText(shCtlCmd, mpsBuffer, sizeof_mpsBuffer);
apsCmdLine = strchr(mpsBuffer, ' '); // first blank
if (NULL == apsCmdLine) // no blank after app
apsCmdLine = mpsBuffer + lstrlen(mpsBuffer);
awCmdLen = apsCmdLine - mpsBuffer + 128;
if (awCmdLen < lstrlen(mpsBuffer))
MessageBeep(0);
SendMessage(shCtlCmd, EM_LIMITTEXT, awCmdLen, 0L);
}
break;
case ID_RB_DEF:
case ID_RB_MIN:
case ID_RB_MAX:
// enable Reset based on clicked radio buttons
if (awCode == BN_CLICKED
|| awCode == BN_DOUBLECLICKED)
if (awParam != siID_RB_SW)
EnableWindow(shCtlReset, YES);
break;
}
switch (awParam)
{
case ID_PB_RESET:
// move the focus to Reset, if it's not there
SetFocus(shCtlReset);
// reset the New Command Line edit control
SendMessage(shCtlCmd, EM_LIMITTEXT, swCmdLen, 0L);
SetWindowText(shCtlCmd, mpsCmdLine);
SendMessage(shCtlCmd, EM_SETSEL, 0, MAKELONG(0, 0xFFFF));
SetFocus(shCtlCmd);
// reset the radio button controls
CheckRadioButton(ahDlg, ID_RB_DEF, ID_RB_MAX, siID_RB_SW);
// reset the button styles
SendMessage(shCtlDefID, BM_SETSTYLE, BS_DEFPUSHBUTTON, 1L);
SendMessage(shCtlReset, BM_SETSTYLE, BS_PUSHBUTTON , 1L);
// fall through
case ID_E_CMD:
case ID_RB_DEF:
case ID_RB_MIN:
case ID_RB_MAX:
// disable Reset based on New Command Line and radio buttons
if (IsDlgButtonChecked(ahDlg, siID_RB_SW))
{
GetWindowText(shCtlCmd, mpsBuffer, sizeof_mpsBuffer);
if (0 == strcmp(mpsBuffer, mpsCmdLine))
EnableWindow(shCtlReset, NO);
}
break;
case ID_PB_EXECUTE:
// if "usage" dialog box, done
if (sbUsage)
{
EndDialog(ahDlg, 0); // OK
break;
}
// get the changed New Command Line
GetWindowText(shCtlCmd, mpsCmdLine, sizeof_mpsCmdLine);
// remove any CR/LFs that were inserted in the edit control
while ((apsCmdLine = strchr(mpsCmdLine, '\r'))
|| (apsCmdLine = strchr(mpsCmdLine, '\n')))
*apsCmdLine = ' ';
// possibly change iCmdShow
if (NO == IsDlgButtonChecked(ahDlg, siID_RB_SW))
{
mnpWinMain->iCmdShow = SW_SHOW;
if (IsDlgButtonChecked(ahDlg, ID_RB_MIN))
mnpWinMain->iCmdShow = SHOW_MINIMIZED;
if (IsDlgButtonChecked(ahDlg, ID_RB_MAX))
mnpWinMain->iCmdShow = SHOW_MAXIMIZED;
}
// fall through
case ID_PB_CANCEL:
EndDialog(ahDlg, awParam); // Execute, Cancel or OK
break;
case ID_PB_USAGE:
// move the focus to Usage, if it's not there
SetFocus(shCtlUsage);
UpdateWindow(ahDlg);
// put up a "usage" dialog box
mhDlg = ahDlg; // required for Usage recursion
argc = 1; // for recursion
WinMain(mnpWinMain->hInst,
mnpWinMain->hPrevInst,
mnpWinMain->lpsCmdLine,
mnpWinMain->iCmdShow);
mhDlg = 0; // required for Usage recursion
// move the focus to the New Command Line edit control
SetFocus(shCtlCmd);
// reset the button styles
SendMessage(shCtlDefID, BM_SETSTYLE, BS_DEFPUSHBUTTON, 1L);
SendMessage(shCtlUsage, BM_SETSTYLE, BS_PUSHBUTTON , 1L);
break;
}
return YES; // did process the message
}
return NO; // didn't process the message
}